package net.pulseproject.router.config.parser;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import net.pulseproject.commons.util.StringPropertyUtil;
import net.pulseproject.commons.util.StringUtil;
import net.pulseproject.router.config.parser.ConfigParserErrors.ParseError;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LineParserImpl implements LineParser {

    private static final Log LOG = LogFactory.getLog(LineParserImpl.class);
    
    private static final String ENTITY_SEPARATOR = "|";

	/**
	 * @param line e.g.: "midiIn1|MidiTransmitModule|module1,module2|port=IAC Driver - MyIn1, channel=16"
	 */
	@Override
	public final LineConfig parseLine(final String line, final int lineNumber, final ConfigParserErrors errors) {
		LOG.trace("parseLine(line=[" + line + "], errors)");
		
		final String[] entities = StringUtil.splitAndTrimElements(line, ENTITY_SEPARATOR);
		
		if(entities.length != 4) {
			String errorDescription = "Parse error on line "+lineNumber+": " +
				"Expected 4 entities but got " + entities.length + "! " +
				"(Separated entities were: " + Arrays.toString(entities) + ")";
			errors.addError(new ParseError(errorDescription ));
			return null;
		}
		
		final String configId = entities[0];
		final String configType = entities[1];
		final String rawConfigOutgoingIds = entities[2];
		final String rawConfigProperties = entities[3];
		
		final String[] splitOutgoingIds = StringUtil.splitAndTrimElements(rawConfigOutgoingIds, ",");
		final Collection<String> outgoingIds = Arrays.asList(splitOutgoingIds);
		
		final String[] splitProperties = StringUtil.splitAndTrimElements(rawConfigProperties, ",");
		final Map<String, Object> properties = new LinkedHashMap<String, Object>();
		for (final String rawProperty : splitProperties) {
			final Entry<String, Object> entry = StringPropertyUtil.parseRawProperty(rawProperty);
			properties.put(entry.getKey(), entry.getValue());
		}
		
		final LineConfig result;
		try {
			result = new LineConfig(configId, configType, outgoingIds, properties);
		} catch(IllegalArgumentException e) {
			String errorDescription = "Parse error on line "+lineNumber+": " + e.getMessage();
			LOG.warn("Could not construct line config by line: [" + line + "]!", e);
			errors.addError(new ParseError(errorDescription ));
			return null;
		}
		return result;
	}

}
